# -*- coding: utf-8 -*-
# created on 2016/12/5

from sympy import diff, simplify, fraction, Abs, sympify, Pow, Add
from mathsolver.functions.shulie.Fundamental import (sl_default_symbol, sl_max_min_index, sl_shulie_name, sl_xiangs,
                                                     sl_xiangs001)


# 判断n**p类型
def sl_np_poly(poly, target_symbol):
    answer = False
    if poly.is_Pow:
        dishu = poly.args[0]
        zhishu = poly.args[1]
        if dishu == target_symbol:
            if not zhishu.has(target_symbol):
                answer = True
    return answer


# 判断a*n+b类型
def sl_linear_n(poly, target_symbol):
    answer = False
    eq_daoshu = diff(poly, target_symbol)
    if not eq_daoshu.has(target_symbol):
        answer = True
    return answer


def sl_er_ci_n(poly, target_symbol):
    answer = False
    eq_daoshu = diff(poly, target_symbol)
    if sl_linear_n(eq_daoshu, target_symbol):
        answer = True
    return answer


# 判断p*an+q类型
def sl_linear_poly(poly, target_symbol):
    answer = False
    m = sl_xiangs001(poly)
    if len(m) == 1:
        eq_daoshu = diff(poly, target_symbol)
        if not eq_daoshu.has(target_symbol):
            answer = True
    return answer


# 判断p*an+q类型
def sl_linear_poly001(poly, target_symbol):
    answer = False
    eq_daoshu = diff(poly, target_symbol)
    if not eq_daoshu.has(target_symbol):
        answer = True
    return answer


# 求: p*an+q 的系数
def sl_linear_poly_coeffs(poly, target_symbol):
    new_poly1 = poly.expand().simplify()
    new_poly1 = new_poly1.subs({target_symbol: sympify('t')})
    a = diff(new_poly1, sympify('t'))
    b = (new_poly1 - a * sympify('t')).expand().simplify()
    return a, b


# 判断a*q**(an+b)类型
def sl_exp_poly(poly, target_symbol):
    answer = False
    new_poly = poly.subs({target_symbol: target_symbol - 1})
    shang = (poly / new_poly).simplify()
    if not shang.has(target_symbol):
        answer = True
    return answer


# 判断等差*等比类型
def sl_dengcha_bi_poly(poly, target_symbol):
    answer = False
    if poly.is_Mul:
        dengcha_part = 1
        deng_bi_part = 1
        for arg in poly.args:
            if arg.is_Pow:
                deng_bi_part = deng_bi_part * arg
            else:
                dengcha_part = dengcha_part * arg
        dengcha_part = simplify(dengcha_part)
        deng_bi_part = simplify(deng_bi_part)
        if sl_exp_poly(deng_bi_part, target_symbol):
            if sl_linear_n(dengcha_part, target_symbol) and dengcha_part.has(target_symbol):
                answer = True
    return answer


# 求等差*等比类型的等差，等比部分
def sl_dengcha_bi_parts(poly):
    dengcha_part = 1
    deng_bi_part = 1
    for arg in poly.args:
        if arg.is_Pow:
            deng_bi_part = deng_bi_part * arg
        else:
            dengcha_part = dengcha_part * arg
    return simplify(dengcha_part), simplify(deng_bi_part)


# 判断(a*a(n)+b)/(c*a(n)+d)类型
def sl_frac_poly(poly, target_symbol):
    answer = False
    m = sl_xiangs(poly)
    if len(m) == 1:
        new_poly = poly.cancel()
        fenzhi, fenmu = fraction(new_poly)
        if sl_linear_poly001(fenzhi, target_symbol) and sl_linear_poly001(fenmu, target_symbol):
            answer = True
    return answer


# 判断: p*a(n+1)+q*a(n)
def sl_benimaru_poly(poly):
    answer = False
    m = sl_xiangs(poly)
    symbol = sl_default_symbol(poly)
    if len(m) == 2:
        shulie_name = sl_shulie_name(poly)
        if len(shulie_name) == 1:
            max_index, min_index = sl_max_min_index(poly)
            if (max_index - min_index) == 1:
                expr1 = 0
                expr2 = 0
                for arg in poly.args:
                    if arg.has(simplify(m[0])) and (not arg.has(simplify(m[1]))):
                        expr1 += arg
                    elif arg.has(simplify(m[1])) and (not arg.has(simplify(m[0]))):
                        expr2 += arg
                    else:
                        answer = False
                if sl_linear_poly(expr1, simplify(m[0])) and sl_linear_poly(expr2, simplify(m[1])):
                    expr1_a, expr1_b = sl_linear_poly_coeffs(expr1, simplify(m[0]))
                    expr2_a, expr2_b = sl_linear_poly_coeffs(expr2, simplify(m[1]))
                    if (not expr1_a.has(symbol)) and (not expr2_a.has(symbol)):
                        if expr1_a != 0 and expr2_a != 0 and expr1_b == 0 and expr1_b == 0:
                            answer = True
    return answer


# 判断: p*a(n+2)+q*a(n+1)+m*a_(n)
def sl_benimaru_poly002(poly):
    answer = False
    m = sl_xiangs001(poly)
    symbol = sl_default_symbol(poly)
    if len(m) == 3:
        shulie_name = sl_shulie_name(poly)
        if len(shulie_name) == 1:
            max_index, min_index = sl_max_min_index(poly)
            if (max_index - min_index) == 2:
                expr1 = 0
                expr2 = 0
                expr3 = 0
                for arg in poly.args:
                    if arg.has(simplify(m[0])) and (not arg.has(simplify(m[1]))) and (not arg.has(simplify(m[2]))):
                        expr1 += arg
                    elif arg.has(simplify(m[1])) and (not arg.has(simplify(m[0]))) and (not arg.has(simplify(m[2]))):
                        expr2 += arg
                    elif arg.has(simplify(m[2])) and (not arg.has(simplify(m[0]))) and (not arg.has(simplify(m[1]))):
                        expr3 += arg
                    else:
                        answer = False
                if sl_linear_poly(expr1, simplify(m[0])) and sl_linear_poly(expr2, simplify(m[1])) and sl_linear_poly(
                        expr3, simplify(m[2])):
                    expr1_a, expr1_b = sl_linear_poly_coeffs(expr1, simplify(m[0]))
                    expr2_a, expr2_b = sl_linear_poly_coeffs(expr2, simplify(m[1]))
                    expr3_a, expr3_b = sl_linear_poly_coeffs(expr3, simplify(m[2]))
                    if (not expr1_a.has(symbol)) and (not expr2_a.has(symbol)) and (not expr3_a.has(symbol)):
                        if (expr1_a != 0 and expr2_a != 0 and expr3_a != 0 and expr1_b == 0 and expr2_b == 0 and
                                expr3_b == 0):
                            answer = True
    return answer


# 求: p*a(n+2)+q*a(n+1)+m*a_(n) 的系数
def sl_benimaru_poly_coeffs002(poly, left_xiang, right_xiang, min_xiang):
    left_coeff, _ = sl_linear_poly_coeffs(poly, left_xiang)
    right_coeff, _ = sl_linear_poly_coeffs(poly, right_xiang)
    min_coeff, _ = sl_linear_poly_coeffs(poly, min_xiang)
    return left_coeff, right_coeff, min_coeff


# 求: p*a(n+1)+q*a(n) 的系数
def sl_benimaru_poly_coeffs(poly):
    max_index, min_index = sl_max_min_index(poly)
    shulie_name = sl_shulie_name(poly)
    max_a, _ = sl_linear_poly_coeffs(poly, shulie_name[0](max_index))
    min_a, _ = sl_linear_poly_coeffs(poly, shulie_name[0](min_index))
    return max_a, min_a


# 判断: p*a(n)**r
def sl_log_poly(poly):
    answer = False
    m = sl_xiangs(poly)
    symbol = sl_default_symbol(poly)
    if len(m) == 1:
        if poly.is_Mul:
            xishu = poly.args[0]
            poly_pow = poly.args[1]
            if not xishu.has(symbol):
                dishu = poly_pow.args[0]
                zhishu = poly_pow.args[1]
                if dishu == simplify(m[0]) and not zhishu.has(symbol):
                    answer = True
        elif poly.is_Pow:
            dishu = poly.args[0]
            zhishu = poly.args[1]
            if dishu == simplify(m[0]) and not zhishu.has(symbol):
                answer = True
    return answer


# 求: p*a(n)**r 的系数
def sl_log_poly_coeffs(poly):
    if poly.is_Mul:
        p = poly.args[0]
        r = poly.args[1].args[1]
        return p, r
    elif poly.is_Pow:
        p = 1
        r = poly.args[1]
        return p, r


# 判断多项式裂项型: 1/(2n-1)*(2n+1)
def sl_liexiang001(poly, target_symbol):
    answer = False
    new_poly = poly.cancel()
    fenzhi, fenmu = fraction(new_poly)
    if fenmu != 1 and not fenzhi.has(target_symbol):
        fenmu = fenmu.factor()
        if fenmu.is_Mul:
            factor_list = []
            for arg in fenmu.args:
                if arg.free_symbols:
                    factor_list.append(arg)
            if len(factor_list) == 2:
                if sl_linear_n(factor_list[0], target_symbol) and sl_linear_n(factor_list[1], target_symbol):
                    p = factor_list[0] - factor_list[1]
                    if not p.has(target_symbol):
                        answer = True
    return answer


# 判断多项式裂项型: 1/(2n-1)*(2n+1)
def sl_liexiang_parts001(poly):
    new_poly = poly.cancel()
    _, fenmu = fraction(new_poly)
    fenmu = fenmu.factor()
    factor_list = []
    coeff = 1
    for arg in fenmu.args:
        if arg.free_symbols:
            factor_list.append(arg)
        else:
            coeff = coeff * arg
    if (factor_list[0] - factor_list[1]) > 0:
        min_xiang = factor_list[1]
        max_xiang = factor_list[0]
    else:
        min_xiang = factor_list[0]
        max_xiang = factor_list[1]
    return 1 / coeff, min_xiang, max_xiang


# 判断多项式裂项型: an = 1/(a*sqrt(f(n)) + b*sqrt(g(n)))
def sl_liexiang002(poly, target_symbol):
    answer = False
    new_poly = poly.cancel()
    fenzhi, fenmu = fraction(new_poly)
    dengcha_parts = []
    symbols = poly.free_symbols
    if not fenzhi.has(target_symbol) and len(symbols) == 1:
        if fenmu.is_Add:
            fenmu_list = []
            for arg in fenmu.args:
                fenmu_list.append(arg)
            parts = []
            index = []
            for item in fenmu_list:
                if item.is_Pow:
                    parts.append(1)
                    parts.append(item.args[0])
                    index.append(0)
                elif item.is_Mul and item.args[1].is_Pow:
                    parts.append(item.args[0])
                    parts.append(item.args[1].args[0])
                    index.append(0)
                else:
                    index.append(1)
            if sum(index) == 0:
                if len(parts) == 4:
                    if parts[0] > 0 and parts[2] > 0:
                        new_tongxiang1 = simplify(parts[0] ** 2 * parts[1])
                        new_tongxiang2 = simplify(parts[2] ** 2 * parts[3])
                        if sl_linear_n(new_tongxiang1, target_symbol) and sl_linear_n(new_tongxiang2, target_symbol):
                            k1, m1 = sl_linear_poly_coeffs(new_tongxiang1, target_symbol)
                            k2, m2 = sl_linear_poly_coeffs(new_tongxiang2, target_symbol)
                            if k1 == k2:
                                answer = True
                                if new_tongxiang1 - new_tongxiang2 > 0:
                                    max_an = new_tongxiang1
                                    min_an = new_tongxiang2
                                    dengcha_parts.append(max_an)
                                    dengcha_parts.append(min_an)
                                else:
                                    max_an = new_tongxiang2
                                    min_an = new_tongxiang1
                                    dengcha_parts.append(max_an)
                                    dengcha_parts.append(min_an)
    return answer, dengcha_parts


# 判断(an+b)/(an+c)类型
def sl_liancheng001(poly, target_symbol):
    answer = False
    new_poly = poly.cancel()
    fenzhi, fenmu = fraction(new_poly)
    if sl_linear_n(fenzhi, target_symbol) and sl_linear_n(fenmu, target_symbol):
        a1, b1 = sl_linear_poly_coeffs(fenzhi, target_symbol)
        a2, b2 = sl_linear_poly_coeffs(fenmu, target_symbol)
        if a1 == a2:
            answer = True
            coeff = 1
        else:
            if a1 == b1:
                if a2 == 1:
                    coeff = a1
                    fenzhi = (fenzhi / a1).expand().simplify()
                    answer = True
            elif a2 == b2:
                if a1 == 1:
                    coeff = a2
                    fenmu = (fenmu / a2).expand().simplify()
                    answer = True
    return answer, coeff, fenzhi, fenmu


# 判断p*a**r类型
def sl_liancheng002(poly, target_symbol):
    answer = False
    coeff = None
    base = None
    exp = None
    if isinstance(poly, Pow):
        coeff = 1
        base = poly.args[0]
        exp = poly.args[1]
        base_symbols = base.free_symbols
        if target_symbol not in base_symbols:
            answer = True
    # elif isinstance(poly, Mul):
    #     print "sl_LianCheng002"
    return answer, coeff, base, exp


# 判断类型: c*|an+b|
def sl_abs_linear_n(poly, target_symbol):
    answer = False
    fn = poly.expand().simplify()
    an = None
    coeff = None
    if fn.is_Mul:
        abs_list = 1
        for arg in fn.args:
            if isinstance(arg, Abs):
                abs_list *= arg
        coeff = fn / abs_list
        if not coeff.has(target_symbol):
            an = abs_list.args[0]
            if sl_linear_n(an, target_symbol):
                answer = True
    elif isinstance(fn, Abs):
        an = fn.args[0]
        coeff = 1
        if sl_linear_n(an, target_symbol):
            answer = True
    return answer, coeff, an


def leijia_parts(poly, target_symbol):
    flag = False
    minus_left = None
    minus_right = None
    step = None
    if isinstance(poly, Add) and len(poly.args) == 2:
        part1, part2 = poly.args

        part1_1 = part1.subs({target_symbol: 10})
        if part1_1 > 0:
            minus_left = part1
            part1_fuhao = 1
        else:
            minus_right = part1
            part1_fuhao = -1

        part2_1 = part2.subs({target_symbol: 10})
        if part2_1 > 0:
            minus_left = part2
            part2_fuhao = 1
        else:
            minus_right = part2
            part2_fuhao = -1

        for i in range(1, 5):
            new_part1 = part1.subs({target_symbol: target_symbol + i})
            new_part2 = part2.subs({target_symbol: target_symbol + i})
            if (new_part1 + part2).expand().simplify() == 0:
                step = i
                break
            elif (new_part2 + part1).expand().simplify() == 0:
                step = i
                break

        if part1_fuhao * part2_fuhao < 0 and step:
            flag = True
    return flag, minus_left, minus_right, step


if __name__ == '__main__':
    pass
